#pragma once
#pragma once
#include "common.h"

class Manager;
class MDMgr;
class CTPTrader;

class CTPMarket : public CThostFtdcMdSpi
	, public std::enable_shared_from_this<CTPMarket>
{
	friend class Manager;
	friend class MDMgr;
	typedef CTPMarket This;
protected:
	boost::asio::io_service& service_;
	//boost::asio::deadline_timer timer_;
	CTPUserLoginInfo userinfo_;
	size_t srv_pos_ = 0;
	std::string userid_;
	CThostFtdcMdApi* api_ = nullptr;
	bool stop_flag_ = false;
	bool normal_flag_ = false;
	std::vector<HZQDB>& subs_;
	std::vector<const char*> codes_;
	size_t code_next_ = 0;
public:
	CTPMarket(boost::asio::io_service& service, std::vector<HZQDB>& subs);

	inline bool is_stop() { return stop_flag_; }
	inline bool is_normal() { return normal_flag_; }
	inline boost::asio::io_service& service() { return service_; }

	bool init(const CTPUserLoginInfo& userinfo, size_t pos);
	void start();
	void stop();

	void subscribe(const std::vector<HZQDB>& subs);
	void unsubscribe(const std::vector<HZQDB>& subs);

protected:
	//void register_timer();
	//void unregister_timer();

protected:
	//以下是当前service线程回调函数

	void set_online();

	void set_offline();

	//void on_timer(const boost::system::error_code& ec);

	void on_subscribe(std::vector<HZQDB>& subs);
	void on_unsubscribe(std::vector<HZQDB>& subs);

	void on_connect();

	void on_disconnect();

	void on_login();

	void on_normal();

	void do_subscribe(const std::vector<HZQDB>& subs);
	void do_unsubscribe(const std::vector<HZQDB>& subs);

	void do_subscribe_next();
	void on_rsp_subscribe_next(const CThostFtdcSpecificInstrumentField& specificInstrument, bool bIsLast);

	void on_market_data_udpate(const CThostFtdcDepthMarketDataField& data);

protected:
	//以下是来自行情回调

	///当客户端与交易后台建立起通信连接时（还未登录前），该方法被调用。
	virtual void OnFrontConnected();

	///当客户端与交易后台通信连接断开时，该方法被调用。当发生这个情况后，API会自动重新连接，客户端可不做处理。
	///@param nReason 错误原因
	///        0x1001 网络读失败
	///        0x1002 网络写失败
	///        0x2001 接收心跳超时
	///        0x2002 发送心跳失败
	///        0x2003 收到错误报文
	virtual void OnFrontDisconnected(int nReason);

	///心跳超时警告。当长时间未收到报文时，该方法被调用。
	///@param nTimeLapse 距离上次接收报文的时间
	virtual void OnHeartBeatWarning(int nTimeLapse) {}

	///登录请求响应
	virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///错误应答
	virtual void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};

	///订阅行情应答
	virtual void OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

	///深度行情通知
	virtual void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData);
};

class MDMgr : public XUtil::XService, public zqdb::NotifyImplT<MDMgr>
{
	friend class Manager;
	typedef MDMgr This;
	typedef XUtil::XService Base;
	typedef zqdb::NotifyImplT<MDMgr> NotifyBase;
protected:
	bool stop_flag_ = false;
	//
	bool sub_all_ = false; 
	std::vector<HZQDB> subs_;
	//size_t MaxProductCountPerExchange_ = 0;
	//size_t MaxCodeCountPerProduct_ = 0;
	size_t MaxDataReservedCount_[CYC_MAX] = { 0 };
	boost::asio::deadline_timer timer_;
	HZQDB holiday_ = nullptr;
	uint32_t tradingday_ = 0;
	std::vector<std::shared_ptr<CTPMarket>> markets_;
	bool online_flag_ = false;
	bool init_flag_ = false;
	std::map<const char*, std::shared_ptr<CTPExchangeInfoEx>, XUtil::strless> init_exchanges_;
	std::map<const char*, std::shared_ptr<CTPProductInfoEx>, XUtil::strless> init_products_;
	std::map<const char*, std::shared_ptr<CTPCommodityInfoEx>, XUtil::strless> init_commoditys_;
	bool normal_flag_ = false;
	std::map<HZQDB, std::array<bool, MDB_FIELD_TABLE_FIELD_COUNT(CTP, CODE)>> pushs_;
	bool push_flag_ = false;
	//
	struct RecordOneInfo
	{
		HZQDB h = nullptr;
		CTPCODEINFO data = { 0 };
		MDB_FIELD diff[MDB_FIELD_TABLE_FIELD_COUNT(CTP, CODE)] = { 0 };
		size_t diff_num = 0;

		void clear()
		{
			h = nullptr;
			diff_num = 0;
		}
	};
	//std::vector<RecordOneInfo> record_infos_;
	RecordOneInfo record_info_;
	std::fstream* record_fs_ = nullptr;
	//bool record_fs_ = false;
	//std::mutex record_mt_;
protected:
	bool IsInstrumentMain(const std::shared_ptr<CTPCommodityInfoEx> Instrument);
	bool IsInstrumentSecond(const std::shared_ptr<CTPCommodityInfoEx> Instrument);
	const char* Instrument2Code(uint32_t tradingday, const std::shared_ptr<CTPCommodityInfoEx> Instrument, char* Code);
	const char* Instrument2Mian(const std::shared_ptr<CTPCommodityInfoEx> Instrument, char* Code);
	const char* Instrument2Second(const std::shared_ptr<CTPCommodityInfoEx> Instrument, char* Code);
	//
	std::map<const char*, std::shared_ptr<ExchangeInfo>, XUtil::strless> init_base(uint32_t trading_day);
	void init_base_data();
	//
	void unregister_timer();
	void register_timer_for_push(size_t millis = 100);
	void on_timer_for_push(const boost::system::error_code& ec);
public:
	static MDMgr& Inst()
	{
		static MDMgr s_inst;
		return s_inst;
	}

	MDMgr();

	//inline boost::asio::io_service& service() { return Base::service(); }
	inline bool is_stop() { return stop_flag_; }
	inline bool is_markets_empty() { return markets_.empty(); } //表示使用官方行情
	inline bool is_online() { return online_flag_; }
	inline bool is_initing() { return init_flag_; }
	inline bool is_normal() { return normal_flag_; }
	inline bool is_subscribe_all() { return sub_all_; }
	inline uint32_t tradingday() { return tradingday_; }

	//外部调用
	void init();
	bool start();
	void run();
	void stop();

	void update_category();

	void on_new_tradingday2(uint32_t trading_day);
	void on_new_tradingday(uint32_t tradingday
		, std::map<const char*, std::shared_ptr<CTPExchangeInfoEx>, XUtil::strless> ctp_exchanges
		, std::map<const char*, std::shared_ptr<CTPProductInfoEx>, XUtil::strless> ctp_products
		, std::map<const char*, std::shared_ptr<CTPCommodityInfoEx>, XUtil::strless> ctp_commoditys
	);

	void on_normal(bool new_trading_day);

	void OnNotifyStatus(HZQDB h);

	void notify(zqdb::Msg& msg);
	void on_module_status(const zqdb::Msg& msg);
	void on_update_msg(const zqdb::Msg& msg);

	int request(zqdb::Msg& msg);

	void subscribe();
	void subscribe(std::shared_ptr<std::set<HZQDB>> subs, std::shared_ptr<std::set<HZQDB>> unsubs);
	
	//int now_data(HZQDB h, PERIODTYPE cycle, void* data);
	int init_data(HZQDB h, PERIODTYPE cycle, zqdb::Msg& msg, HZQDB base = nullptr);
	int update_data(HZQDB h, MDB_FIELD* diff_field, size_t diff_field_num, CODEINFO* data);
	int update_data_ex(HZQDB h, const CTPCODEINFO& new_code, MDB_FIELD* diff_field, size_t diff_field_num);
	int build_data(HZQDB h, PERIODTYPE cycle, zqdb::Msg& msg);
	bool exist_data(HZQDB h, PERIODTYPE cycle);
	int load_data(HZQDB h, PERIODTYPE cycle, std::string& data);
	int save_data(HZQDB h, PERIODTYPE cycle, zqdb::Msg& msg);
	int close_data(HZQDB h, PERIODTYPE cycle);
	
	void close_record();
	void save_record(HZQDB h = nullptr, MDB_FIELD* diff_field = nullptr, size_t diff_field_num = 0, CTPCODEINFO* data = nullptr);
	void test_record(uint32_t& date, uint32_t& time);

	void set_offline(std::shared_ptr<CTPMarket> market);
	void set_online(std::shared_ptr<CTPMarket> market); 
	void on_online(bool online_flag);

	void begin_new_tradingday();
	void clear_new_tradingday();
	void init_new_tradingday();
	void end_new_tradingday();
	bool update_data_price(CTPCODEINFO& code, const CThostFtdcDepthMarketDataField& data);
	void update_data(const CThostFtdcDepthMarketDataField& data);
	void update_data(HZQDB h, const CThostFtdcDepthMarketDataField& data, const CThostFtdcInstrumentStatusField* status = nullptr);
	void update_msg(const com::zqdb::proto::msg::RtnSubscribe& msg);
	void update_status(const CThostFtdcInstrumentStatusField& status);
	void update_status(const char* Exchange, const char* Product, const char* Code, const CThostFtdcInstrumentStatusField& status);
};
